package com.leo.cloud.system.config;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * 文件名：CacheServiceImpl.java
 *
 */
@Service("cacheService")
public class RedisUtil {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 查询缓存
     * @param key 缓存键 不可为空
     */
    public <T> T get(String key) {
        return get(key, null, null, null);
    }

//
//    public boolean lock(String k,String v,long milliseconds){
//        System.out.println("--加锁-->"+k+"-->"+v);
//        boolean b = redisTemplate.getRequiredConnectionFactory().getConnection().setNX(k.getBytes(), v.getBytes());
//        if(!b){
//            try {
//                Thread.sleep(50L);// 等待加锁 .
//                System.out.println("--等待加锁-->"+k+"-->"+v);
//            }catch (Exception e){}
//            b = lock(k, v, milliseconds);
//        }
//        return b;
//    }
//    public boolean releaseLock(String k,String v){
//        String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
//        Object o= redisTemplate.getRequiredConnectionFactory().getConnection().eval(luaScript.getBytes(), ReturnType.INTEGER, 1,k.getBytes(),v.getBytes());
//        return o != null&&"1".equals(String.valueOf(o));
//    }

    /**
     * 查询缓存
     * @param key      缓存键 不可为空
     * @param function 如没有缓存，调用该callable函数返回对象 可为空
     */
    public <T> T get(String key, Function<String, T> function) {
        return get(key, function, key, null);
    }

    /**
     * 查询缓存
     *
     * @param key      缓存键 不可为空
     * @param function 如没有缓存，调用该callable函数返回对象 可为空
     * @param funcParm function函数的调用参数
     */
    public <T, M> T get(String key, Function<M, T> function, M funcParm) {
        return get(key, function, funcParm, null);
    }

    /**
     * 查询缓存
     *
     * @param key        缓存键 不可为空
     * @param function   如没有缓存，调用该callable函数返回对象 可为空
     * @param expireTime 过期时间（单位：毫秒） 可为空
     */
    public <T> T get(String key, Function<String, T> function, Long expireTime) {
        return get(key, function, key, expireTime);
    }

    /**
     * 查询缓存
     *
     * @param key        缓存键 不可为空
     * @param function   如没有缓存，调用该callable函数返回对象 可为空
     * @param funcParm   function函数的调用参数
     * @param expireTime 过期时间（单位：毫秒） 可为空
     */
    @SuppressWarnings("unchecked")
    public <T, M> T get(String key, Function<M, T> function, M funcParm, Long expireTime) {
        T obj = null;
        if (StringUtils.isEmpty(key)) {
            return null;
        }
        expireTime = getExpireTime(expireTime,null);
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            obj = (T) operations.get(key);
            if (function != null && obj == null) {
                obj = function.apply(funcParm);
                if (obj != null) {
                    set(key, obj, expireTime);// 设置缓存信息
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 设置缓存键值 直接向缓存中插入值，这会直接覆盖掉给定键之前映射的值
     *
     * @param key 缓存键 不可为空
     * @param obj 缓存值 不可为空
     */
    public <T> void set(String key, T obj) {
        set(key, obj, null);
    }

    /**
     * 设置缓存键值 直接向缓存中插入值，这会直接覆盖掉给定键之前映射的值
     *
     * @param key        缓存键 不可为空
     * @param obj        缓存值 不可为空
     * @param expireTime 过期时间（单位：毫秒） 可为空
     */
    public <T> void set(String key, T obj, Long expireTime) {
        if (StringUtils.isEmpty(key)) {
            return;
        }
        if (obj == null) {
            return;
        }
        expireTime = getExpireTime(expireTime,null);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        operations.set(key, obj);
        if(expireTime != null )
            redisTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
    }

    /**
     * 移除缓存
     *
     * @param key 缓存键 不可为空
     */
    public void remove(String key) {
        if (StringUtils.isEmpty(key)) {
            return;
        }
        redisTemplate.delete(key);
    }

    /**
     * 是否存在缓存
     *
     * @param key 缓存键 不可为空
     */
    public boolean contains(String key) {
        return redisTemplate.hasKey(key);
        //return redisTemplate.countExistingKeys(Collections.singletonList(key))>0;
//        if (StringUtil.isEmpty(key)) {
//            return false;
//        }
//        return null != get(key);
    }

    /**
     * 获取过期时间 单位：毫秒
     *
     * @param expireTime 传人的过期时间 单位毫秒 如小于1分钟，默认为10分钟
     */
    private Long getExpireTime(Long expireTime,Long defaultVal) {
        Long result = expireTime;
        if (expireTime == null) {
            result = defaultVal;
        }
        return result;
    }

    /**
     * 批量移除缓存
     * @param key 缓存键 不可为空
     */
    public void batchRemove(String key) {
        Set<String> set = redisTemplate.keys(key + "*");
        if (set != null) {
            for (String item : set) {
                redisTemplate.delete(item);
            }
        }
    }

    public long getExpire(String key) {
        return redisTemplate.getExpire(key);
    }
}
